 <template>
  <transition name="fade" @after-leave="handleAfterLeave">
    <div class="ant-message-notice" v-if="visible">
      <div
        class="ant-message-notice-content"
        @mouseleave="!config.duration ? () => {} : startTimer()"
        @mouseenter="!config.duration ? () => {} : clearTimer()"
      >
        <div
          class="ant-message-custom-content"
          :class="'ant-message-' + config.type"
        >
          <component
            :is="config.icon ? config.icon : getDefaultIcon"
          ></component>
          <span>{{ config.content }}</span>
        </div>
      </div>
    </div>
  </transition>
</template>

<script>
import {
  CheckCircleOutlined,
  CloseCircleOutlined,
  ExclamationCircleOutlined,
  LoadingOutlined,
} from "@ant-design/icons-vue";
import { h } from "vue";
export default {
  name: "Message",
  props: {
    config: {
      type: Object,
      default: function () {
        return {
          top: `100px`,
          duration: 3000,
          type: "success",
        };
      },
    },
  },
  components: {
    CheckCircleOutlined,
    CloseCircleOutlined,
    ExclamationCircleOutlined,
    LoadingOutlined,
  },
  computed: {
    getDefaultIcon() {
      let icon;
      if (this.config.type == "success") {
        icon = this.$options.components.CheckCircleOutlined;
      } else if (this.config.type == "error") {
        icon = this.$options.components.CloseCircleOutlined;
      } else if (this.config.type == "warning") {
        icon = this.$options.components.ExclamationCircleOutlined;
      } else if (this.config.type == "loading") {
        icon = this.$options.components.LoadingOutlined;
      } else {
        icon = this.$options.components.ExclamationCircleOutlined;
      }
      return icon;
    },
  },
  data() {
    return {
      visible: false,
      timer: null,
    };
  },
  mounted() {
    this.visible = true;
    if (this.config.duration != 0) {
      this.setTimer(); // 组件挂载的时候开始计时，计时完成移除
    }
  },
  methods: {
    setTimer() {
      // 组件停留时间duration
      this.timer = setTimeout(() => {
        this.close();
      }, this.config.duration * 1000);
    },
    close() {
      this.visible = false;
      if (this.config.onClose) {
        this.config.onClose();
      }
      clearTimeout(this.timer);
    },
    clearTimer() {
      //鼠标移入提醒框时，清除定时器，提醒框持久化显示
      console.log("清除定时器，不会自动消失");
      clearTimeout(this.timer);
    },
    startTimer() {
      // 鼠标离开提醒框，定时器开始计时
      console.log("开始定时器");
      this.setTimer();
    },
    handleAfterLeave() {
      console.log("动画执行完成");
      // 移除动画执行完成后，销毁组件，并将其从父节点移除
      this.$emit("end", this.config.key);
    },
  },
  beforeUnmount() {
    console.log("组件死亡");
  },
  render() {
    console.log("render");
    // `<div><slot></slot></div>`
    return h("div", {}, this.$slots.default());
  },
  watch: {
    config: {
      handler: function (newVal) {
        if (newVal.duration == 0) {
          this.close();
        }
        this.clearTimer();
        this.setTimer();
      },
      deep: true,
    },
  },
};
</script>

<style lang="stylus" scoped>
.ant-message-notice {
  padding: 8px;
  text-align: center;

  .ant-message-notice-content {
    display: inline-block;
    padding: 10px 16px;
    background: #fff;
    border-radius: 2px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    pointer-events: all;

    .anticon {
      position: relative;
      top: 1px;
      margin-right: 8px;
      font-size: 16px;
    }
  }

  .ant-message-info .anticon, .ant-message-loading .anticon {
    color: #1890ff;
  }

  .ant-message-warning .anticon {
    color: rgb(250, 173, 20);
  }

  .ant-message-error .anticon {
    color: rgb(245, 34, 45);
  }

  .ant-message-success .anticon {
    color: rgb(82, 196, 26);
  }
}

.fade-enter-active {
  animation: fadeIn 0.3s ease;
}

.fade-leave-active {
  animation: fadeOut 0.3s ease;
}

@keyframes fadeIn {
  0% {
    max-height: 0;
    padding: 0;
    opacity: 0;
  }

  100% {
    max-height: 150px;
    padding: 8;
    opacity: 1;
  }
}

@keyframes fadeOut {
  0% {
    max-height: 150px;
    padding: 8px;
    opacity: 1;
  }

  100% {
    max-height: 0;
    padding: 0;
    opacity: 0;
  }
}
</style>